/*
  cpgf Library
  Copyright (C) 2011 Wang Qi http://www.kbasm.com/
  All rights reserved.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
*/


#ifndef __GMETAMETHOD_H
#define __GMETAMETHOD_H

#include "cpgf/private/gmetamethod_p.h"


namespace cpgf {


GMAKE_FINAL(GMetaMethod)

class GMetaMethod : public GMetaCallable, GFINAL_BASE(GMetaMethod)
{
private:
	typedef GMetaCallable super;

public:
	template <typename OT, typename FT, typename Policy>
	static GMetaMethod * newMethod(const char * name, const FT & func, const Policy & policy) {
		GASSERT_STATIC(IsFunction<FT>::Result);

		GMetaMethod * method = new GMetaMethod(name, createMetaType<FT>(), meta_internal::GMetaMethodCallbackMaker<OT, typename GFunctionTraits<FT>::ObjectType>::make(func), policy);

		method->addModifier(meta_internal::GMetaMethodCallbackMaker<OT, typename GFunctionTraits<FT>::ObjectType>::modifiers);

		return method;
	}

public:
	template <typename CT, typename Policy>
	GMetaMethod(const char * name, const GMetaType & itemType, const CT & callback, const Policy & policy)
		: super(name, itemType, mcatMethod), baseData(new meta_internal::GMetaMethodData<CT, Policy>(callback, policy)) {
	}

	virtual GMetaType getParamType(size_t index) const;
	virtual size_t getParamCount() const;
	virtual bool hasResult() const;
	virtual GMetaType getResultType() const;
	virtual bool isVariadic() const;


	virtual GVariant execute(void * instance, const GVariant * params, size_t paramCount) const;

	virtual bool checkParam(const GVariant & param, size_t paramIndex) const;

	virtual bool isParamTransferOwnership(size_t paramIndex) const;
	virtual bool isResultTransferOwnership() const;
	
	virtual GMetaConverter * createResultConverter() const;

#define REF_INVOKE(N, unused) GVariant invoke(void * instance GPP_COMMA_IF(N) GPP_REPEAT(N, GPP_COMMA_PARAM, const GVariant & p)) const;

	GPP_REPEAT_2(REF_MAX_ARITY, REF_INVOKE, GPP_EMPTY)

#undef REF_INVOKE

protected:
	GScopedPointer<meta_internal::GMetaMethodDataBase> baseData;
};


GMAKE_FINAL(GMetaConstructor)

class GMetaConstructor : public GMetaCallable, GFINAL_BASE(GMetaConstructor)
{
private:
	typedef GMetaCallable super;

public:
	template <typename CT, typename Policy>
	GMetaConstructor(const CT & callback, const Policy & policy)
		: super(meta_internal::arityToName(CT::TraitsType::Arity).c_str(), createMetaType<typename CT::TraitsType::FullType>(), mcatConstructor),
			baseData(new meta_internal::GMetaMethodData<CT, Policy>(callback, policy)) {
	}

	virtual GMetaType getParamType(size_t index) const;
	virtual size_t getParamCount() const;
	virtual bool hasResult() const;
	virtual GMetaType getResultType() const;
	virtual bool isVariadic() const;

	virtual GVariant execute(void * instance, const GVariant * params, size_t paramCount) const;

	virtual bool checkParam(const GVariant & param, size_t paramIndex) const;

	virtual bool isParamTransferOwnership(size_t paramIndex) const;
	virtual bool isResultTransferOwnership() const;

	virtual GMetaConverter * createResultConverter() const;

#define REF_NEW_INSTANCE(N, unused) \
	void * invoke(GPP_REPEAT(N, GPP_COMMA_PARAM, const GVariant & p)) const;

	GPP_REPEAT_2(REF_MAX_ARITY, REF_NEW_INSTANCE, GPP_EMPTY)

#undef REF_NEW_INSTANCE

protected:
	GScopedPointer<meta_internal::GMetaMethodDataBase> baseData;
};


} // namespace cpgf



#endif
